﻿using System;
using System.Collections.Generic;

namespace Murry.DataStore
{
    /// <summary>
    /// Supported Entities.
    /// </summary>
    public static class Entities
    {
        private static readonly Dictionary<Type, Dictionary<Type, Type>> SupportedEntityTypes = new Dictionary<Type, Dictionary<Type, Type>>();

        /// <summary>
        /// Add entity type to the supported entity type.
        /// </summary>
        /// <param name="dataStoreType">DataStore type.</param>
        /// <param name="interfaceType">Interface type.</param>
        /// <param name="implementedType">Implemented type.</param>
        public static void AddEntity(Type dataStoreType, Type interfaceType, Type implementedType)
        {
            if (dataStoreType == null)
            {
                throw new ArgumentNullException("dataStoreType");
            }

            if (dataStoreType.GetInterface("IReadOnlyDataStore") == null)
            {
                throw new ArgumentException("dataStoreType must implement the IReadOnlyDataStore interface.");
            }

            if (interfaceType == null)
            {
                throw new ArgumentNullException("interfaceType");
            }

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException("interfaceType must be an interface.");
            }

            if (implementedType == null)
            {
                throw new ArgumentNullException("implementedType");
            }

            lock (SupportedEntityTypes)
            {
                if (!SupportedEntityTypes.ContainsKey(dataStoreType))
                {
                    SupportedEntityTypes[dataStoreType] = new Dictionary<Type, Type>();
                }

                SupportedEntityTypes[dataStoreType][interfaceType] = implementedType;
            }
        }

        /// <summary>
        /// Is an entity type supported by a database type?
        /// </summary>
        /// <param name="dataStoreType">Database type.</param>
        /// <param name="interfaceType">Interface type.</param>
        /// <returns>True if supported.</returns>
        public static bool IsSupported(Type dataStoreType, Type interfaceType)
        {
            return SupportedEntityTypes.ContainsKey(dataStoreType) && SupportedEntityTypes[dataStoreType].ContainsKey(interfaceType);
        }

        /// <summary>
        /// Get implemented entity type for a given DataStore Type and Interface Type.
        /// </summary>
        /// <param name="dataStoreType">DataStore Type.</param>
        /// <param name="interfaceType">Interface Type.</param>
        /// <returns>Implemented Type.</returns>
        public static Type GetImplementedEntityType(Type dataStoreType, Type interfaceType)
        {
            if (!IsSupported(dataStoreType, interfaceType))
            {
                throw new ArgumentException("Type {0} is not supported.", interfaceType.FullName);
            }

            lock (SupportedEntityTypes)
            {
                var implementedType = SupportedEntityTypes[dataStoreType][interfaceType];
                return implementedType;
            }
        }
    }
}
